package com.summer.guardedSuspension;

import java.util.concurrent.Callable;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionVarBlocker implements Blocker {
	
	private final Lock lock;
	private final Condition condition;
	
	public ConditionVarBlocker(){
		lock = new ReentrantLock();
		condition = lock.newCondition();
	}
	
	public ConditionVarBlocker(Lock lock){
		this.lock = lock;
		condition = lock.newCondition();
	}

	public <V> V callWithGuard(GuardedAction<V> guardedAction) throws Exception {
		lock.lockInterruptibly();
		V result;
		try{
			final Predicate predicate = guardedAction.guard;
			while(!predicate.evaluate()){
				condition.await();
			}
			result = guardedAction.call();
			return result;
		}finally{
			lock.unlock();
		}
	}

	public void signalAfter(Callable<Boolean> stateOperation) throws Exception {
		lock.lockInterruptibly();
		try{
			if(stateOperation.call()){
				condition.signal();
			}
		}finally{
			lock.unlock();
		}
	}

	public void signal() throws InterruptedException {
		lock.lockInterruptibly();
		try{
			condition.signal();
		}finally{
			lock.unlock();
		}
	}

	public void broadcastAfter(Callable<Boolean> stateOperation) throws Exception {
		lock.lockInterruptibly();
		try{
			if(stateOperation.call()){
				condition.signalAll();
			}
		}finally{
			lock.unlock();
		}
	}

}
